/**
 * @author luzeyu & liangqiaowei
 */
package tiei.ajp.huffman.utils;

import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class TestAll {
    @Test
    public void testTree() {
        // --- Test build tree
        HuffmanTree<Byte> tree = new HuffmanTree<>();
        tree.addNode(new TreeNode<>(1, (byte) 0xa));
        tree.addNode(new TreeNode<>(2, (byte) 0xb));
        tree.addNode(new TreeNode<>(4, (byte) 0xc));
        tree.addNode(new TreeNode<>(8, (byte) 0xd));
        TreeNode<Byte> root = tree.buildTree();

        assert root.right.freq == 8;
        assert root.left.freq == 7;

        assert root.left.right.freq == 4;
        assert root.left.left.freq == 3;

        assert root.left.left.right.freq == 2;
        assert root.left.left.left.freq == 1;

        System.out.println("Test pass : build tree");

        // --- Test traverse tree
        assert root.data == null;
        List<TreeNode<Byte>> nodeList = tree.preorderTraverse();
        for (int i = 0; i < nodeList.size(); i++) {
            if (i == 0) assert nodeList.get(i).freq == 15;
            if (i == 1) assert nodeList.get(i).freq == 7;
            if (i == 2) assert nodeList.get(i).freq == 3;
        }
        System.out.println("Test pass : traverse tree");

        // --- Test serialize tree
        List<Byte> arr = tree.serializeTree();
        byte[] arrRef = new byte[]{1, 1, 1, 0, 0xa, 0, 0xb, 0, 0xc, 0, 0xd};
        for (int i = 0; i < arr.size(); i++) {
            assert arr.get(i).equals(arrRef[i]);
        }
        System.out.println("Test pass : serialize tree");


    }

    @Test
    public void testDeserialize() {
        // --- Test deserialize tree
        byte[] arrRef = new byte[]{1, 1, 1, 0, 0xa, 0, 0xb, 0, 0xc, 0, 0xd};
        List<Byte> lst = new ArrayList<>();
        for (byte b : arrRef) lst.add(b);
        HuffmanTree<Byte> anotherTree = new HuffmanTree<>(lst);
        TreeNode<Byte> anotherRoot = anotherTree.getTreeRoot();
        assert anotherRoot.right.data == 0xd;
        assert anotherRoot.left.right.data == 0xc;
        assert anotherRoot.left.left.right.data == 0xb;
        assert anotherRoot.left.left.left.data == 0xa;
        System.out.println("Test pass : deserialize tree");
    }

    @Test
    public void testCalB() {
        byte tmp = 0;
        long bitNum = 1;
        byte numB = (byte) (bitNum >= (1L << 56) ? 8 :
                bitNum >= (1L << 48) ? 7 :
                        bitNum >= (1L << 40) ? 6 :
                                bitNum >= (1L << 32) ? 5 :
                                        bitNum >= (1L << 24) ? 4 :
                                                bitNum >= (1L << 16) ? 3 :
                                                        bitNum >= (1L << 8) ? 2 :
                                                                bitNum >= (1L << 0) ? 1 : 0);
        for (int i = 0; i < 8; i++) {
            byte lsb = (byte) ((bitNum >> (8 * i)) & 0xff);
            if (lsb != 0) tmp = (byte) (i + 1);
        }
        assert numB == tmp;


        bitNum = 5;
        numB = (byte) (bitNum >= (1L << 56) ? 8 :
                bitNum >= (1L << 48) ? 7 :
                        bitNum >= (1L << 40) ? 6 :
                                bitNum >= (1L << 32) ? 5 :
                                        bitNum >= (1L << 24) ? 4 :
                                                bitNum >= (1L << 16) ? 3 :
                                                        bitNum >= (1L << 8) ? 2 :
                                                                bitNum >= (1L << 0) ? 1 : 0);
        for (int i = 0; i < 8; i++) {
            byte lsb = (byte) ((bitNum >> (8 * i)) & 0xff);
            if (lsb != 0) tmp = (byte) (i + 1);
        }
        assert numB == tmp;

        bitNum = 256;
        numB = (byte) (bitNum >= (1L << 56) ? 8 :
                bitNum >= (1L << 48) ? 7 :
                        bitNum >= (1L << 40) ? 6 :
                                bitNum >= (1L << 32) ? 5 :
                                        bitNum >= (1L << 24) ? 4 :
                                                bitNum >= (1L << 16) ? 3 :
                                                        bitNum >= (1L << 8) ? 2 :
                                                                bitNum >= (1L << 0) ? 1 : 0);
        for (int i = 0; i < 8; i++) {
            byte lsb = (byte) ((bitNum >> (8 * i)) & 0xff);
            if (lsb != 0) tmp = (byte) (i + 1);
        }
        assert numB == tmp;

        bitNum = 65536;
        numB = (byte) (bitNum >= (1L << 56) ? 8 :
                bitNum >= (1L << 48) ? 7 :
                        bitNum >= (1L << 40) ? 6 :
                                bitNum >= (1L << 32) ? 5 :
                                        bitNum >= (1L << 24) ? 4 :
                                                bitNum >= (1L << 16) ? 3 :
                                                        bitNum >= (1L << 8) ? 2 :
                                                                bitNum >= (1L << 0) ? 1 : 0);
        for (int i = 0; i < 8; i++) {
            byte lsb = (byte) ((bitNum >> (8 * i)) & 0xff);
            if (lsb != 0) tmp = (byte) (i + 1);
        }
        assert numB == tmp;

        System.out.println("Test passed");
    }


    @Test
    public void testFileReader() throws IOException {
        byte[] arr = new byte[]{
                // Magic num
                (byte) 0x04, (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe,
                // Huffman Tree
                (byte) 0x01, (byte) 0x00, (byte) 0xdd, (byte) 0x00, (byte) 0xee,
                // Bit num
                (byte) 0x04, (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, (byte) 0xaa,
                // Compressed data
        };
        ByteArrayInputStream byteArrInputStream = new ByteArrayInputStream(arr);
        FileReader fr = new FileReader(byteArrInputStream);

        assert fr.readMagicNum() == (long) (0x00000000bebafecaL);
        List<Byte> serializedTree = fr.readTree();
        assert serializedTree.size() == 5;
        assert serializedTree.get(4) == (byte) 0xee;

        System.out.println("Test pass");
    }

    @Test
    public void testFileWriter() throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
//
//        FileWriter fw = new FileWriter(bos);
//        fw.writeInt(0xcafebabe);
//

        byte[] arr = bos.toByteArray();
    }


}
